package org.demo.test.socket.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

import org.apache.log4j.Logger;

public class NIOSocketServer {

	private static Logger log = Logger.getLogger(NIOSocketServer.class.getClass());
	
	public static void main(String args[]) throws Exception{
		int port = 6666;
		ServerSocketChannel ssc = ServerSocketChannel.open();
		// 设置为非阻塞
		ssc.configureBlocking(false);
		ServerSocket ss = ssc.socket();
		ss.setReuseAddress(true);
        ss.bind(new InetSocketAddress(port));
        
        
        Selector selector = Selector.open();
        ssc.register(selector, SelectionKey.OP_ACCEPT);
        try{
        	while(true){
        		if(selector.select(2000)==0){
        			continue;
        		}
        		log.info("获取到了关注的事件");
        		Iterator<SelectionKey> selectionKeys = selector.selectedKeys().iterator();
        		while(selectionKeys.hasNext()){
        			SelectionKey readyKey = selectionKeys.next();
        			selectionKeys.remove();
        			SelectableChannel selectableChannel = readyKey.channel();
        			
        			if(readyKey.isValid() && readyKey.isAcceptable()){
        				log.info("==channel已经准备就绪==");
        				ServerSocketChannel serverSocketChannel = (ServerSocketChannel)selectableChannel;
        				SocketChannel sc = serverSocketChannel.accept();
        				log.info("==socket连接就绪==");
        				registerSocketChannel(sc,selector);
        			}else if(readyKey.isValid() && readyKey.isReadable()){
        				log.info("==socket channel data readable!==");
        				readSocketChannel(readyKey);
        			}
        		}
        	}
        	
        }catch(Exception e){
        	e.printStackTrace();
        }
	}
	
	/**
	 * 注册数据读取事件监听
	 * @param sc
	 * @param selector
	 * @throws Exception
	 */
	private static void registerSocketChannel(SocketChannel sc, Selector selector)
		throws Exception{
		sc.configureBlocking(false);
		sc.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(2048));
	}
	
	private static void readSocketChannel(SelectionKey readyKey){
		SocketChannel sc = (SocketChannel)readyKey.channel();
		ByteBuffer bb = (ByteBuffer)readyKey.attachment();
		int realLen = -1;
		try {
			realLen = sc.read(bb);
			if(realLen == -1) {
				log.error("缓存区没有可读取数据");
				return;
			}
			bb.flip();
			byte[] messageBytes = bb.array();
			String messageEncode = new String(messageBytes,"UTF-8");
			String message = URLDecoder.decode(messageEncode, "UTF-8");
			if(message.indexOf("#") != -1){
				bb.clear();
				log.info("数据包内容：" + message);
				log.info("数据接收完毕！");
				ByteBuffer sendBuffer = ByteBuffer.wrap(URLEncoder.encode("接收成功", "UTF-8").getBytes());
				sc.write(sendBuffer);
				sc.close();
			}else{
				log.info("未完全传输，数据包内容：" + message);
				bb.position(realLen);
				bb.limit(bb.capacity());
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			try {
				if(sc != null) sc.close();
			} catch (IOException ee) {
				// TODO Auto-generated catch block
				ee.printStackTrace();
			}
		}
	}
}
